#define SDL_MAIN_HANDLED

#include <SDL2/SDL.h>
#include <SDL2/SDL_mouse.h>

#include "SFC_Inc.hpp"
#include "Setup.h"
#include "GraphLib.h"
#include "Platform.h"

class SDLSystem : public PlatformSystem
{
private:
	SDL_Window *MainWnd;
	SDL_Surface *MainSurface;
	int Width, Height;
public:
	SDLSystem();
	~SDLSystem();

	void CreateHostInterface(const char *title, int& w, int& h) override;
	Surface GetBufferSurface() override;
	void UpdateWindow(Surface surface) override;

	void Delay(Uint32 ms) override;

	void EventPackage(SDL_Event *event);
	void StartListenWithThread() override;
	void StopListenWithThread() override;
};

PlatformSystem *OutsideSystem = nullptr;

void InitIOSystem()
{
	OutsideSystem = new SDLSystem();
}

SDLSystem::SDLSystem()
{
	SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS | SDL_INIT_TIMER);
}

SDLSystem::~SDLSystem()
{
	SDL_DestroyWindow(this->MainWnd);
	this->MainWnd = nullptr;
	OutsideSystem = nullptr;
	SDL_Quit();
}

void SDLSystem::CreateHostInterface(const char *Title, int& w, int& h)
{
	this->MainWnd = SDL_CreateWindow(Title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, w, h, SDL_WINDOW_SHOWN);
	SDL_GetWindowSize(this->MainWnd, &w, &h);
	this->Width = w;
	this->Height = h;
}

void SDLSystem::UpdateWindow(Surface surface)
{
	// Copy Surface to SDL_Surface
	SDL_LockSurface(this->MainSurface);
	memcpy(this->MainSurface->pixels, surface->data, this->MainSurface->w * this->MainSurface->h * sizeof(Uint32));
	SDL_UnlockSurface(this->MainSurface);
	SDL_UpdateWindowSurface(this->MainWnd);
}


Surface SDLSystem::GetBufferSurface()
{
	this->MainSurface = SDL_GetWindowSurface(this->MainWnd);
	Surface sur = CreateSurface(this->MainSurface->w, this->MainSurface->h);
	return sur;
}


void SDLSystem::EventPackage(SDL_Event *event)
{
	SFC_Event se;
	// Package Event
	switch(event->type)
	{
	case SFC_MOUSE_MOVE:
	case SFC_MOUSE_DOWN:
	case SFC_MOUSE_UP:
		se.Type = EventType::Mouse;
		se.Forcus = { (int)SFC_MOUSE_X, (int)SFC_MOUSE_Y };
		switch (event->type)
		{
		case SFC_MOUSE_MOVE:	se.Mouse.Type = MouseEventType::Move;	break;
		case SFC_MOUSE_DOWN:	se.Mouse.Type = MouseEventType::Down;	break;
		case SFC_MOUSE_UP:		se.Mouse.Type = MouseEventType::Up;		break;
		}
		break;
	case SDL_QUIT:
		se.Type = EventType::Window;
		se.Power.Type = PowerEventType::Shutdown;
		break;
	}
	this->EventQueue.Put(se);
}

#ifdef __ANDROID__
static int EventWatcher(void *, SDL_Event* event)
{
	((SDLSystem*)OutsideSystem)->EventPackage(event);
	return 0;
}

void SDLSystem::StartListenWithThread()
{
	SDL_AddEventWatch(EventWatcher, nullptr);
}

void SDLSystem::StopListenWithThread()
{
	SDL_DelEventWatch(EventWatcher, nullptr);
}
#else
pthread_t ntid;
bool ListenSig = true;
void *EventWatcher(void*)
{
	SDL_Event Event;
	while (ListenSig)
	{
		std::cout << "Wait Event" << std::endl;
		if (SDL_PollEvent(&Event) == 1)
		{
			((SDLSystem*)OutsideSystem)->EventPackage(&Event);
		}
	}
	return nullptr;
}
void SDLSystem::StartListenWithThread()
{
	pthread_create(&ntid, NULL, EventWatcher, NULL);
}
void SDLSystem::StopListenWithThread()
{
	ListenSig = false;
	pthread_join(ntid, NULL);
}
#endif
void SDLSystem::Delay(Uint32 ms)
{
	clock_t end = clock() + ms * (CLOCKS_PER_SEC / 1000);
	while (clock() < end) ;
}
